package com.sky.aspect;

import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 *切面，增强mapper类的update喝insert 方法，自动填充公共字段
 */
@Aspect
@Component
@Slf4j
public class AutoFillAspect {

    //定义切入点
    //* com.sky.mapper.*.*(..)：这个表达式匹配 com.sky.mapper 包及其子包中的所有方法。* 表示任意返回类型，*.* 表示任意类名和方法名，(..) 表示任意参数列表。
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void  AutoFillPointCut(){
    }

    //定义前置通知，增强方法
    @Before("AutoFillPointCut()")
    public  void autoFill(JoinPoint joinpoint){
        log.info("(切面)开始进行公共字段填充。。。");

        //获取当前被拦截方法上的数据库操作类型
        MethodSignature signature = (MethodSignature)joinpoint.getSignature();//获取方法签名
        AutoFill annotation = signature.getMethod().getAnnotation(AutoFill.class);//获取注解
        OperationType operationType = annotation.value();//获取注解对应类型

        //获取当前被拦截方法的参数--实体对象
        Object[] args = joinpoint.getArgs();
        if (args == null || args.length==0){
            return ;
        }
        //约定使用这个注解，方法中第一个参数必须是实体
        Object arg = args[0];

        //准备赋值的数据
        LocalDateTime now = LocalDateTime.now();
        Long currentId = BaseContext.getCurrentId();

        //根据不同的操作类型，给对应的属性赋值，利用反射，
        if(operationType== OperationType.INSERT){
            //新增数据
            //先获取实体set方法对象
            try {
                Method setCreateTime = arg.getClass().getMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                Method setCreateUser = arg.getClass().getMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                Method setUpdateTime = arg.getClass().getMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = arg.getClass().getMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

                setCreateTime.invoke(arg,now);
                setCreateUser.invoke(arg,currentId);
                setUpdateTime.invoke(arg,now);
                setUpdateUser.invoke(arg,currentId);

            } catch (Exception e) {
                throw new RuntimeException(e);
            }

        }else{
            //修改数据
            try {

                Method setUpdateTime = arg.getClass().getMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = arg.getClass().getMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

                setUpdateTime.invoke(arg,now);
                setUpdateUser.invoke(arg,currentId);

            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}
